public class Main {
    public static void main(String[] args) {
        System.out.println("Hello world!");
         // 数据库 索引
        //  索引是为了加快查询的速度
        // 索引背后的数据结构

        // 最关键的结构是B+树
        //  B+树就是为了数据库索引量身定做的数据结构~~

        // 了解B+树呢要先了解B+树的前身B树
        // B+树就是B树的改进版

        // B树也叫B-树
        // （B杠树）
        // B树 可以认为是一个N叉搜索树

        // 先来回忆回忆什么是树的度 ： 树的度就是 所有节点的度的最大值，节点的度就是有几个孩子


        //而一个B树呢 作为一个N叉树
        // 一个节点里面可以保存多个节点
        // 例如： 跟节点先保存为 30 40 50 60 这四个数据
        // 那么通过这个数据可以向下划分为这几个区间：
        // 小于30  大于30小于40  大于40小于50  大于50小于60  大于60  （5个区间）
        // 同理 这几个区间还能继续往下划分
        // 值到把数据分完

        // 当节点的子树多了，节点上保存的key就多了
        // 意味着在同样key的个数的前提下
        // B树的高度就要比 二叉搜索树低 很多
        // **** 树的高度影响了磁盘访问的素的****
        // 树的高度越高，进行查询比较的时候访问磁盘的次数就越多
        // 最好的特点就是降低树的高度

        // 接下来就是B+树
        // B+树就是在B树的基础上继续改进 (也是N叉搜索树)

        // 例如 根节点给先给两个数据 ： 8    15
        // 那么 接下来只会分为两组：
        //  小于8  大于8小于15
        // 注意！！！此处的15相当于最大值~~~没有大于15的元素了！！
        // 接下来继续往下分
        // 例如为 [2 5 8]     [11 15]
        // 注意这时候 8 在父节点中有了 在子节点又来一遍 15也是
        // 等排到最后的时候要把全部的叶子节点连接起来

        // B+的特点：
        // 1. 一个节点，可以存储N个key，N个key划分出了N个区间~~~而不是（N+1个区间）
        // 2.每个节点中的key的值，都会在子结点中也存在（同时key是子节点的最大值）
        // 3.B+树的叶子节点，是首位相连，类似于一个链表
        // 4. 整个树的所有数据都是包含在 叶子 节点中的！！！
        // （所有的非叶子节点中的key 最终都会出现在叶子节点中）
        // 5. 由于叶子节点是完整的数据集合，只在叶子节点这里存储数据表的每一行数据。
        //   而非叶子节点，只存key值本身即可


        // 注意每个节点里面存储的数据都必须是可比较的
        // 而碰巧的是数据结构的所有数据类型都是可以比较的


        //B+树的优点
        // 1. 当前一个节点保存更多的key，最终树的高度是相对更矮的，查询的时候减少了IO访问次数。（和B树是一样的）
        // 2. 所有的查询最终都会落到叶子节点上。（查询任何一个数据没经过的IO访问次数，是一样的）
        // 3. B+树的所有的叶子节点，构成链表，此时比较方便进行范围查询 ~ ~
        // 4.由于数据都在叶子节点上，非叶子节点只存储key，导致非叶子节点占用空间是比较小的~~ 这些非叶子节点就可能在内存中缓存（
        // 或者是缓存一部分），又进一步减小了IO的次数


        // 如果表里有多个索引呢？
        //针对id有主键索引
        // 针对name又一个索引
        // 此时：表的数据还是按照id为主键，构建出B+树 通过叶子节点组织所有的数据行~~
        // 其次，针对name这一列 会另外构建一个B+树
        // 但是这个B+树的叶子节点就不再存储这一行的完整数据，
        // 而是存主键id是啥 ，还需要再通过主键id去主键的B+树里再查一次~ ~
        // （查两次B+树）
        // 上述过程为“回表”，这个过程都是mysql自动完成的。用户感知不到



        // 接下来就讲讲什么是 事务 ！！！
        // 比如两个人要进行转账
        //  1 给 2 500 （假设 1 里面有 1000 2 里面没有钱）
        // 此时要执行一下sql操作
        // 1.  update account set balance = balance - 500 where id = 1;
        // 2.  update account set balance = balance + 500 where id = 2;
        // 要分两步执行
        // 而此时如果再转账的过程中 突然没有信号了 ， 数据库炸了或者宕机了
        // 而1又已经交过钱了
        // 那么此时只会执行第一条语句 而 第二条语句
        // 那么此时的结果就是 1 少了500 而 2 还是没有钱
        // 那么此时用到 事务
        // 事务就是把这两条语句封装一块
        // 那么就是 要么全部执行要么全部不执行


        // 事务的本质就是 把多个sql语句打包成一个整体  <---（事务的原子性）
        // 要么全部执行要么全部不执行  （这里的不执行不是真的没执行，而是执行力执行到一半出错了。出错之后，选择了回复现场，把数据还原成未执行之前
        // 的状态）  （这个恢复数据的操作叫做”回滚“（rollback））；
        // 而不会出现“执行一半“这样的中间件状态
        //
        // 进行“回滚”的时候 咋知道回滚的是恢复到啥样的状态呢
        // 这就是需要额外的部分来记录事务中的操作步骤
        //（数据库里专门有一个用来记录事务的日志）.
        // 正因如此 使用事务的时候 执行 的sql的开销是更大的，效率更低

        //2.2 事务的概念
        //事务指逻辑上的一组操作，组成这组操作的各个单元，要么全部成功，要么全部失败。
        //在不同的环境中，都可以有事务。对应在数据库中，就是数据库事务

        // ****数据库的事务，有四个关键特性（八股文）：

        // 1. 原子性~【最核心的特性】 初心~
        // 2. 一致性 事务执行前后，数据是靠谱的不能不科学~
        // 3. 持久性 事务修改的内容是写到硬盘的，持久存在的。重启后也不丢失~
        // ****4.隔离性****

        // 隔离性 是为了解决”并发“执行事务引起的问题
        //  并发是指一个处理器同时处理多个任务。
        //并行是指多个处理器或者是多核的处理器同时处理多个不同的任务。
        // 来个比喻：并发是一个人同时吃三个馒头，而并行是三个人同时吃三个馒头。
        // 并发(concurrency)：指在同一时刻只能有一条指令执行，但多个进程指令被快速的轮换执行，
        // 使得在宏观上具有多个进程同时执行的效果，但在微观上并不是同时执行的，只是把时间分成若干段，使多个进程快速交替的执行。


        // 接下来讲讲 并发执行事务可能产生的问题：

        // 一.脏读问题：
        // 一个事务A正在对数据进行修改的过程中，还没提交之前，另一个事务B，也对同一个数据进行了读取。 此时的B的读操作就成为
        // ”脏读“， 读到的数据也成为”脏数据“

        // 为了解决这个问题 mysql 引入了”写操作加锁“这样的机制
        // 写的时候不能用，写完才可以用
        // 写加锁
        // 这个操作降低了并发程度（降低了效率），但是提高了隔离性（提高了数据的准确性）


        // 二。不可重复读问题： （已经定好了 写加锁）
        // 事务1 已经提交了数据，此时事务2 开始去读取数据，在读取过程中，事务3又提交了新的数据。
        // 此时意味着同一个事务2之内，多次读取数据，读出来的结果是不相同的~~（预期是一个事务中，多次读取到的结果一样）
        // 第二次的读取结果并与能复现第一次的结果 ~ ~

        // 为了解决这个问题要进行 ”读加锁“
        // 通过这个读加锁 又进一步的降低了事务的并发处理能力（处理效率也降低了），提高了事务的隔离性（数据的准确性又提高了）

        // 三。幻读
        // 当前一定预定了读加锁和写加锁，解决了不可重复读和脏读的问题
        // 在读加锁和写加锁的前提下，一个事务两次读取同一个数据，发现读取的数据值是一样的，但是结果不一样~ ~
        // 这种就是幻读

        // 解决办法就是 ： 数据库使用”串行化“这样的方式来解决幻读，彻底放弃并发处理事务，一个接一个的串行的处理事务。
        // 这样做，并发程度是最低的（效率最慢的），隔离性是最高的（准确性也是最高的）


        // 针对上述问题 mysql 提供了4种隔离级别

        // read uncommitted 没有进行任何锁限制，并发最高（效率最高），隔离性最低（准确性最低）
        // read committed 给了写加锁     并发程度降低 ， 隔离性提高了
        // repeatable read 给写和读都加锁  并发程度又降低 ， 隔离性又提高了
        // serializable 串行化  并发程度最低，隔离性最高

        // 这四个级别是mysql内置的机制
        // 可以通过修改mysql的配置文件，来设置当前的mysql工作在哪种状态
        // 这里面的加锁都是mysql内部机制 不是代码


        // 这几个级别没有好坏
        // 在准确性 和 效率之间经行权衡
        // 看实际需求和业务场景
        // 例如：转账的时候准确性要求拉满，效率不关键
        // 而对于抖音点赞那就要求快 要求效率 ，准确性就不关键




    }
}